using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Windows.Forms;

using Aphysoft.Vate.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Threading;

namespace Aphysoft.Vate.Editor
{
    public partial class VateEditor : System.Windows.Forms.Form
    {
        #region Properties
        /// <summary>
        /// Debug component.
        /// </summary>
        private Debug debug = null;
        /// <summary>
        /// Editor service container.
        /// </summary>
        private static ServiceProvider serviceProvider = null;
        /// <summary>
        /// Editor content manager.
        /// </summary>
        private static ContentManager content = null;
        /// <summary>
        /// Editor content manager. 
        /// </summary>
        public static ContentManager Content
        {
            get { return content; }
        }
        /// <summary>
        /// Render target.
        /// </summary>
        private Control renderPanel = null;
        /// <summary>
        /// Gets or sets render target.
        /// </summary>
        public Control RenderPanel
        {
            get { return renderPanel; }
            set { renderPanel = value; }
        }
        /// <summary>
        /// Render is running or not.
        /// </summary>
        private bool run = false;
        /// <summary>
        /// Gets a value indicating the render is running.
        /// </summary>
        public bool Run
        {
            get { return run; }
        }
        /// <summary>
        /// TODO: Gets window/render state is active or not.
        /// </summary>
        public bool IsActive
        {
            get { return true ; }
        }
        private bool applyChanges = false;
        #endregion

        #region Constructor
        /// <summary>
        /// Create base editor.
        /// </summary>
        protected VateEditor()
        {
            serviceProvider = new ServiceProvider();
            //graphicsDeviceManager = new GraphicsDeviceService();
            serviceProvider.AddService<IGraphicsDeviceService>(this);

            // Init content manager
            Vate.Content = new ContentManager(serviceProvider);
            Vate.Content.RootDirectory = Vate.ContentRootDirectory;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Runs XNA Application in specified render target.
        /// </summary>
        protected void Start()
        {
            if (RenderPanel != null)
            {
                run = true;
                Initialize();
            }
        }

        public void EditorReset()
        {
            if (Vate.Device != null)
            {
                applyChanges = true;
            }
        }

        public void ApplyChanges()
        {
            applyChanges = false;

            PresentationParameters pp = PresentationParametersSetup();

            Vate.Device.Reset(pp);
        }

        /// <summary>
        /// Do application events.
        /// </summary>
        public void DoEvents()
        {
            if (run)
            {        
                Update(null);

                Draw(null);

                Vate.Device.Present();
            }
        }

        #endregion

        #region Initialize

        private void Initialize()
        {
            GraphicsSetup();
#if DEBUG
            // Debug
            debug = new Debug(10);
            Debug.Write("Debug Initialized.");
#endif          
            // camera manager
            CameraManager.Init();

            // projector manager
            ProjectorManager.Init();

            // Initialize as device being reset         
            GraphicsDeviceReset(null, EventArgs.Empty);

            // line manager
            Line.Init();

            // Init editor
            EditorInitialize();

            LoadContent();
        }

        #region Initialize Virtualization
        protected virtual void EditorInitialize()
        {
        }
        #endregion

        #endregion
        
        #region LoadContent

        private void LoadContent()
        {
            Vate.GlobalAlphaSpriteBatch = new SpriteBatch(Vate.Device);

            Vate.GlobalAdditiveSpriteBatch = new SpriteBatch(Vate.Device);

#if DEBUG
            Debug.Write("Loading Content...");
#endif
            EditorLoadContent();
#if DEBUG
            Debug.Write("Content Loaded.");
#endif

#if DEBUG
            // Debug load content
            debug.LoadContent();
#endif
        }

        #region LoadContent Virtualization
        protected virtual void EditorLoadContent()
        {
        }
        #endregion

        #endregion

        #region UnloadContent

        private void UnloadContent()
        {
            EditorUnloadContent();

            Vate.GlobalAlphaSpriteBatch.Dispose();
        }

        #region UnloadContent Virtualization
        protected virtual void EditorUnloadContent()
        {
        }
        #endregion

        #endregion

        #region Update

        private void Update(GameTime gameTime)
        {
            #region Input
            if (IsActive)
            {
                Vate.KeyboardState = Keyboard.GetState();
                Vate.MouseState = Mouse.GetState();
            }
            #endregion

            // Game time update
            Vate.TimeUpdate(gameTime);
#if DEBUG
            // Debug update
            debug.Update(gameTime);
#endif

            EditorUpdate(gameTime);

            #region Input Finallized
            Vate.OldKeyboardState = Vate.KeyboardState;
            Vate.OldMouseState = Vate.MouseState;
            #endregion
        }

        #region Update Virtualization
        protected virtual void EditorUpdate(GameTime gameTime)
        {
        }
        #endregion

        #endregion

        #region Draw

        private void Draw(GameTime gameTime)
        {
            // Begin ProjectorManager
            ProjectorManager.Begin();

            // Clear
            Vate.Device.Clear(Color.SlateBlue);

            // Begin Global Additive Sprite Batch, Global Alpha Sprite Batch
            Vate.GlobalAdditiveSpriteBatch.Begin(SpriteBlendMode.Additive);
            Vate.GlobalAlphaSpriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            // Benchmarking
#if DEBUG
            Vate.ResetInputTriangle();
#endif

            // Game Draw for Default Projector
            if (ProjectorManager.DefaultProjector.IsRender)
            {
                // Draw Projector Scene
                EditorDraw(gameTime);

                // Line Manager
                Line.Draw();
            }

            // Game Draw for other projector in projector manager
            if (ProjectorManager.Projectors.Count > 0)
            {
                foreach (KeyValuePair<string, Projector> projectorEntry in ProjectorManager.Projectors)
                {
                    string gameProjectorName = projectorEntry.Key;
                    Projector gameProjector = projectorEntry.Value;

                    ProjectorManager.Current = gameProjectorName;
                    Vate.Device.Viewport = gameProjector.Viewport;

                    // Draw Projector Scene
                    EditorDraw(gameTime);

                    // Line Manager
                    Line.Draw();
                }
            }

            // End ProjectorManager
            ProjectorManager.End();

#if DEBUG
            // Debug draw
            debug.Draw(gameTime);
#endif

            // End Global Alpha Sprite Batch, Additive Sprite Batch
            Vate.GlobalAlphaSpriteBatch.End();
            Vate.GlobalAdditiveSpriteBatch.End();

            // Time update
            Vate.TimeDraw(gameTime);

            if (applyChanges)
            {
                ApplyChanges();
            }
        }

        #region Draw Virtualization
        protected virtual void EditorDraw(GameTime gameTime)
        {
        }
        #endregion

        #endregion
    }
}
